package com.dj.util;

import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import com.alibaba.druid.util.StringUtils;
import com.dj.repository.EncounterRespository;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.utilities.xhtml.NodeType;
import org.hl7.fhir.utilities.xhtml.XhtmlNode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.function.BiFunction;
import java.util.function.Function;

/**
 * @author cyf
 * @description
 * @create 2018-06-27 14:21
 **/
@Component
public class CrudOperationUtil {

    private static final Logger logger = LoggerFactory.getLogger(CrudOperationUtil.class);

    @Autowired
    private EncounterRespository encounterRespository;

    //创建
//    public static <T> MethodOutcome create(T t , Function<T , IdType> savePatient){
//        //保存到数据库
//        IdType theId = savePatient.apply(t);
//        return CrudOperationUtil.getMethodOutcome(theId);
//    }


    //更新
//    public static <T> MethodOutcome update(IdType theId, T t, BiFunction<String,T,IdType> updateFunction){
//        String id = theId.getIdPart();
//        IdType idType = updateFunction.apply(id, t);
//        if(id.equals(idType.getIdPart())){
//            return getMethodOutcome(idType);
//        } else {
//            throw new ResourceNotFoundException("Update data failure");
//        }
//    }


    /**
     * 创建和更新的统一返回
     *
     * @param theId
     * @return
     */
    public static MethodOutcome getMethodOutcome(IdType theId, long startTime) {
        long endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;

        logger.info("Time of use " + totalTime + " ms !");
        MethodOutcome methodOutcome = new MethodOutcome();
        methodOutcome.setId(theId);

        String message = "Successfully created resource \"" + theId + "\" in " + totalTime + "ms";
        String result = "No issues detected during validation";


        XhtmlNode xhtmlNode = new XhtmlNode(NodeType.Element, "div");
        xhtmlNode.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
        xhtmlNode.h1().addText("Operation Outcome");

        XhtmlNode table = xhtmlNode.addTag("table");
        table.setAttribute("border", "0");
        XhtmlNode tr = table.tr();
        tr.td().setAttribute("style", "font-weight: bold;").addText("INFORMATION");
        tr.td().addText("[]");
        tr.td().pre().addText(message);

        tr.td().setAttribute("style", "font-weight: bold;").addText("INFORMATION");
        tr.td().addText("[]");
        tr.td().pre().addText(result);

        OperationOutcome outcome = new OperationOutcome();
        outcome.setText(new Narrative()
                .setStatus(Narrative.NarrativeStatus.GENERATED)
                .setDiv(xhtmlNode));


    /*
    <issue>
        <severity value="information"/>
        <code value="informational"/>
        <diagnostics value="Successfully created resource &quot;Patient/4427931/_history/1&quot; in 3ms"/>
    </issue>
    <issue>
        <severity value="information"/>
        <code value="informational"/>
        <diagnostics value="No issues detected during validation"/>
    </issue>
    */
        outcome.addIssue()
                .setSeverity(OperationOutcome.IssueSeverity.INFORMATION)
                .setCode(OperationOutcome.IssueType.INFORMATIONAL)
                .setDiagnostics(message);
        //.setLocation(theLocation);
        outcome.addIssue()
                .setSeverity(OperationOutcome.IssueSeverity.INFORMATION)
                .setCode(OperationOutcome.IssueType.INFORMATIONAL)
                .setDiagnostics(result);

    /*
    <id value="297ef1686420fcb20164210082ef0003"/>
	<meta>
		<versionId value="1"/>
	</meta>
    */

        outcome.setId(theId);
        outcome.setMeta(new Meta().setLastUpdated(new Date()));
        methodOutcome.setOperationOutcome(outcome);
        return methodOutcome;
    }


    // Function<T , R>  java 8 语法， T 返回实体类，R 代表传入参数类型
    // BiFunction 类似

    //读取
    public static <T> T readOrVRead(IdType theId, Function<String, T> getByIdFunction, BiFunction<String, String, T> getByIdAndVersionBiFunction) {
        T retVal;
        try {
            // 获取资源id
            String id = theId.getIdPart();
            retVal = getByIdFunction.apply(id);
            // 如果存在版本号，说明更新过，查询历史版本
            if (retVal != null && theId.hasVersionIdPart()) {
                retVal = getByIdAndVersionBiFunction.apply(id, theId.getVersionIdPart());
            }
        } catch (Exception e) {
            logger.error("The resource was not found, the cause is {}", e.getCause());
            throw new ResourceNotFoundException("The resource was not found");
        }
        return retVal;
    }

    //删除
    public static MethodOutcome delete(IdType theId, Function<String, Boolean> deleteByT, long startTime) {
        long endTime = System.currentTimeMillis();
        long totalTime = endTime - startTime;

        logger.info("Time of use " + totalTime + " ms !");

        String message = "Successfully deleted 1 resource(s) in " + totalTime + "ms";
        String result = "No issues detected during validation";

        MethodOutcome methodOutcome = new MethodOutcome();
        OperationOutcome outcome = new OperationOutcome();

        XhtmlNode xhtmlNode = new XhtmlNode(NodeType.Element, "div");
        xhtmlNode.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
        xhtmlNode.h1().addText("Operation Outcome");

        XhtmlNode table = xhtmlNode.addTag("table");
        table.setAttribute("border", "0");
        XhtmlNode tr = table.tr();
        tr.td().setAttribute("style", "font-weight: bold;").addText("INFORMATION");
        tr.td().addText("[]");
        tr.td().pre().addText(message);

        tr.td().setAttribute("style", "font-weight: bold;").addText("INFORMATION");
        tr.td().addText("[]");
        tr.td().pre().addText(result);

        //判断需要删除的记录是否存在
        String id = theId.getIdPart();
        if (StringUtils.isEmpty(id)) {
//            outcome.addIssue()
//                    .setSeverity(OperationOutcome.IssueSeverity.INFORMATION)
//                    .setCode(OperationOutcome.IssueType.INFORMATIONAL)
//                    .setDiagnostics("Successfully deleted 1 resource(s) ");
//            //.setLocation(theLocation);
//            outcome.addIssue()
//                    .setSeverity(OperationOutcome.IssueSeverity.INFORMATION)
//                    .setCode(OperationOutcome.IssueType.INFORMATIONAL)
//                    .setDiagnostics("No issues detected during validation");


            outcome.addIssue().setDiagnostics("Couldn't delete because this id doesn't exist");
            methodOutcome.setOperationOutcome(outcome);
            return methodOutcome;
        }
        //删除记录
        Boolean deleteResult = deleteByT.apply(id);
        if (deleteResult) {

            outcome.setText(new Narrative()
                    .setStatus(Narrative.NarrativeStatus.GENERATED)
                    .setDiv(xhtmlNode));

            outcome.addIssue()
                    .setSeverity(OperationOutcome.IssueSeverity.INFORMATION)
                    .setCode(OperationOutcome.IssueType.INFORMATIONAL)
                    .setDiagnostics(message);
            //.setLocation(theLocation);
            outcome.addIssue()
                    .setSeverity(OperationOutcome.IssueSeverity.INFORMATION)
                    .setCode(OperationOutcome.IssueType.INFORMATIONAL)
                    .setDiagnostics(result);


            methodOutcome.setOperationOutcome(outcome);
        } else {
            throw new ResourceVersionConflictException("delete was failure");
        }
        return methodOutcome;
    }

    /**
     *  根据患者id 和就诊id 查询数据为空返回xml 模板
     * @param flag
     * @return
     */
    public static MethodOutcome getEmptyMethodOutcome(Integer flag) {

        MethodOutcome methodOutcome = new MethodOutcome();

        String message = "Exception,The associated " + (flag == 0 ? " patient " : " encounter or patient ") +" ID is empty, creating a failure.";
        String result = "No issues detected during validation";


        XhtmlNode xhtmlNode = new XhtmlNode(NodeType.Element, "div");
        xhtmlNode.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
        xhtmlNode.h1().addText("Operation Outcome");

        XhtmlNode table = xhtmlNode.addTag("table");
        table.setAttribute("border", "0");
        XhtmlNode tr = table.tr();
        tr.td().setAttribute("style", "font-weight: bold;").addText("INFORMATION");
        tr.td().addText("[]");
        tr.td().pre().addText(message);

        tr.td().setAttribute("style", "font-weight: bold;").addText("INFORMATION");
        tr.td().addText("[]");
        tr.td().pre().addText(result);

        OperationOutcome outcome = new OperationOutcome();
        outcome.setText(new Narrative()
                .setStatus(Narrative.NarrativeStatus.GENERATED)
                .setDiv(xhtmlNode));
        outcome.addIssue()
                .setSeverity(OperationOutcome.IssueSeverity.INFORMATION)
                .setCode(OperationOutcome.IssueType.INFORMATIONAL)
                .setDiagnostics(message);
        outcome.addIssue()
                .setSeverity(OperationOutcome.IssueSeverity.INFORMATION)
                .setCode(OperationOutcome.IssueType.INFORMATIONAL)
                .setDiagnostics(result);
        methodOutcome.setOperationOutcome(outcome);
        return methodOutcome;
    }

    public static < T extends DomainResource> T getQueryEmpty(T t,String msg) {
        // 错误消息
        String message = "Resource "+ msg +" is not known";
        XhtmlNode xhtmlNode = new XhtmlNode(NodeType.Element, "div");
        xhtmlNode.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
        xhtmlNode.h1().addText("Operation Outcome");

        XhtmlNode table = xhtmlNode.addTag("table");
        table.setAttribute("border", "0");
        XhtmlNode tr = table.tr();
        tr.td().setAttribute("style", "font-weight: bold;").addText("ERROR");
        tr.td().addText("[]");
        tr.td().pre().addText(message);
        t.setText(new Narrative()
                .setStatus(Narrative.NarrativeStatus.GENERATED)
                .setDiv(xhtmlNode));
        return t;
    }

    //public static Bundle getBundleQueryEmpty(Bundle bundle, String msg) {
    //    // 错误消息
    //    String message = "Resource "+ msg +" is not known";
    //    XhtmlNode xhtmlNode = new XhtmlNode(NodeType.Element, "div");
    //    xhtmlNode.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
    //    xhtmlNode.h1().addText("Operation Outcome");
    //
    //    XhtmlNode table = xhtmlNode.addTag("table");
    //    table.setAttribute("border", "0");
    //    XhtmlNode tr = table.tr();
    //    tr.td().setAttribute("style", "font-weight: bold;").addText("ERROR");
    //    tr.td().addText("[]");
    //    tr.td().pre().addText(message);
    //
    //    bundle.setText(new Narrative()
    //            .setStatus(Narrative.NarrativeStatus.GENERATED)
    //            .setDiv(xhtmlNode));
    //    return bundle;
    //}


    //    public static <T> MethodOutcome delete(IdType theId, Function<String,T> queryById , Function<T , Boolean> deleteByT) {
//        MethodOutcome retVal = new MethodOutcome();
//        OperationOutcome outcome = new OperationOutcome();
//        //判断需删除记录是否存在
//        String id = theId.getIdPart();
//        T t = queryById.apply(id);
//        if (t == null) {
//            outcome.addIssue().setDiagnostics("This id doesn't exist");
//            retVal.setOperationOutcome(outcome);
//            return retVal;
//        }
//        //删除记录
//        Boolean deleteResult = deleteByT.apply(t);
//        if (deleteResult) {
//            outcome.addIssue().setDiagnostics("delete was successful");
//
//            retVal.setOperationOutcome(outcome);
//        } else {
//            throw new ResourceVersionConflictException("This id delete failure");
//        }
//        return retVal;
//    }


//    public static MethodOutcome getIdAfterDelete(Date date) {
//        MethodOutcome methodOutcome = new MethodOutcome();
//        OperationOutcome outcome = new OperationOutcome();
//
//        String message = "Resource was deleted at " ;
//
//        XhtmlNode xhtmlNode = new XhtmlNode(NodeType.Element, "div");
//        xhtmlNode.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
//        xhtmlNode.h1().addText("Operation Outcome");
//
//        XhtmlNode table = xhtmlNode.addTag("table");
//        table.setAttribute("border", "0");
//        XhtmlNode tr = table.tr();
//        tr.td().setAttribute("style","font-weight: bold;").addText("ERROR");
//        tr.td().addText("[]");
//        tr.td().pre().addText(message);
//
//
//
//        outcome.addIssue()
//                .setSeverity(OperationOutcome.IssueSeverity.INFORMATION)
//                .setCode(OperationOutcome.IssueType.INFORMATIONAL)
//                .setDiagnostics("Successfully deleted 1 resource(s) ");
//        return methodOutcome;
//    }

}
